package com.jay.lang.clazz;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import com.jay.lang.clazz.ClassCls.MyAnnotation;
import com.jay.lang.clazz.ClassCls.What;

@What(description = "An annotation test class")
@MyAnnotation(stringValue = "for class", intValue = 100)
public class ClassCls {
	static void printClassName(Object obj) {
		System.out.println("The class of " + obj + " is "
				+ obj.getClass().getName());
	}

	static Runnable testInner() {
		return new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub

			}

		};
	}

	private Runnable testInner2() {
		return new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub

			}

		};
	}

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		System.out.println("All about names");
		printClassName(new Integer(0));
		System.out.println(ClassCls.class.getName());
		System.out.println(ClassCls.class.getSimpleName());
		System.out.println(ClassCls.class.getCanonicalName());
		System.out.println(Sub.class.getName());
		System.out.println(Sub.class.getSimpleName());
		System.out.println(Sub.class.getCanonicalName());
		String[] sa = new String[] {};
		System.out.println(sa.getClass().getName());
		System.out.println(sa.getClass().getSimpleName());
		System.out.println(sa.getClass().getCanonicalName());
		System.out.println(sa.getClass().getComponentType());

		// Enum
		System.out.println("Enum");
		printClassName(Operations.DIVIDE);
		System.out.println(Operations.class.isEnum());
		System.out.println(Operations.class.getEnumConstants());

		// Modifier
		System.out.println("Modifier");
		System.out.println(ClassCls.class.getModifiers());
		System.out.println(Base.class.getModifiers());

		// classloader
		System.out.println("Class loader");
		System.out.println(ClassCls.class.getClassLoader());

		// enclosing
		System.out.println("Enclosing");
		System.out.println(ClassCls.class.getEnclosingClass());
		System.out.println(Sub.class.getEnclosingClass());
		System.out.println(testInner().getClass().getEnclosingMethod());

		// asSubclass
		System.out.println("subclass");
		Super sub = new Sub();
		printClassName(sub);
		System.out.println(sub.getClass().getSuperclass().getName());
		System.out.println(sub.getClass()
				.asSubclass(sub.getClass().getSuperclass()).getName());

		// cast 一般用于反射
		Sub sub2 = Sub.class.cast(sub);
		Sub sub3 = (Sub) sub;
		// forname
		System.out.println(Class.forName("com.jay.lang.clazz.ClassCls"));
		System.out.println(Class
				.forName("com.jay.lang.clazz.ClassCls$Operations"));

		// getAnnotations
		Annotation[] annos = ClassCls.class.getAnnotations();

		System.out.println("All annotations for ClassCls:");
		for (Annotation a : annos)
			System.out.println(a);

		// getClasses
		Class<?>[] clses = ClassCls.class.getDeclaredClasses();
		System.out.println("All classes for ClassCls:");
		for (Class<?> a : clses) {
			System.out.println(a + "|" + a.isSynthetic());
		}

		// getFields
		Field[] fs = ClassCls.class.getFields();
		System.out.println("All fields for ClassCls:");
		for (Field a : fs)
			System.out.println(a);

		// getMethods
		Method[] methods = ClassCls.class.getMethods();
		System.out.println("All methods for ClassCls:");
		for (Method a : methods)
			System.out.println(a);

		// getConstructors
		Constructor<?>[] cs = ClassCls.class.getConstructors();
		System.out.println("All constructors for ClassCls:");
		for (Constructor<?> a : cs)
			System.out.println(a);

		// Miscellaneous
		System.out.println("Miscellaneous");
		System.out.println(ClassCls.class.getSigners());
		System.out.println(ClassCls.class.getPackage());
		System.out.println(ClassCls.class.getProtectionDomain());
		System.out.println(ClassCls.class.getResource("/1.txt"));
		System.out
				.println(ClassCls.class.getClassLoader().getResource("1.txt"));
		System.out.println(ClassCls.class.isSynthetic());
		ClassCls cc = new ClassCls();
		System.out.println(ClassCls.class.isSynthetic());
		System.out.println(cc.testInner2().getClass().isAnonymousClass());
		System.out.println(cc.testInner2().getClass().isMemberClass());
		System.out.println(cc.testInner2().getClass().isLocalClass());
		cc.new Base1();
		System.out.println(Class.forName("com.jay.lang.clazz.ClassCls$1").isSynthetic());
		System.out.println(Class.forName("com.jay.lang.clazz.$Proxy2").isSynthetic());
		
		//newInstance
		ClassCls.class.newInstance();
		Base.class.newInstance();
	}

	// warning
	<T> T doSomething() {
		Object o = new Object();
		return (T) o;
	}

	// use cast, no warning
	<T> T doSomething(Class<T> cls) {
		Object o = new Object();
		return cls.cast(o);
	}

	// extends sample
	static class Super {
		public Super(){
			
		}

	}

	public static class Sub extends Super {

	}

	// enum sample
	public enum Operations {
		PLUS {
			double apply(double x, double y) {
				return x + y;
			}
		},
		MINUS {
			double apply(double x, double y) {
				return x - y;
			}
		},
		TIMES {
			double apply(double x, double y) {
				return x * y;
			}
		},
		DIVIDE {
			double apply(double x, double y) {
				return x / y;
			}
		};
		abstract double apply(double x, double y);
	}

	// A simple annotation type.
	@Retention(RetentionPolicy.RUNTIME)
	@interface MyAnnotation {
		String stringValue();

		int intValue();
	}

	@Retention(RetentionPolicy.RUNTIME)
	@interface What {
		String description();
	}

	// bridge method to seperate the two methods
	class Base {
//		public Base(){
//			
//		}
		Base method() {
			return new Base();
		}
	}

	class Derived extends Base {
		private Derived() {
		};

		Derived method() {
			return new Derived();
		}
	}

	private class Base1 {
		private Base1() {
		}
	}
}
